package pl.edu.agh.sr.lab3.zad2.impl.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAPackage.ServantNotActive;
import org.omg.PortableServer.POAPackage.WrongPolicy;

import pl.edu.agh.sr.lab3.zad2.generated.AFactoryPOA;
import pl.edu.agh.sr.lab3.zad2.generated.Item;
import pl.edu.agh.sr.lab3.zad2.generated.ItemAlreadyExists;
import pl.edu.agh.sr.lab3.zad2.generated.ItemBusy;
import pl.edu.agh.sr.lab3.zad2.generated.ItemHelper;
import pl.edu.agh.sr.lab3.zad2.generated.ItemNotExists;

public class AFactoryImpl extends AFactoryPOA {

	private POA poa = null;

	Object itemsManageLock = new Object();
	List<ItemImpl> itemList = new ArrayList<ItemImpl>();
	List<ItemAImpl> itemAList = new ArrayList<ItemAImpl>();
	List<ItemBImpl> itemBList = new ArrayList<ItemBImpl>();
	List<ItemCImpl> itemCList = new ArrayList<ItemCImpl>();
	Map<String, Boolean> busyItemsMap = new HashMap<String, Boolean>();

	public AFactoryImpl(POA rootpoa) {
		System.out.println("In AFactoryImpl()");
		poa = rootpoa;
	}

	@Override
	public Item create_item(String name, String type) throws ItemAlreadyExists {
		System.out.println("In AFactoryImpl::create_item(): " + name + " "
				+ type);

		Item retItem = null;
		synchronized (itemsManageLock) {
			if (isItemCreated(name)) {
				throw new ItemAlreadyExists("Item already exists: " + name);
			}

			if (type.toUpperCase().equals("ITEM")) {
				System.out.println("Creating item: " + name);
				ItemImpl itemImpl = new ItemImpl(name);
				itemList.add(itemImpl);
				busyItemsMap.put(name, true);
				try {
					retItem = ItemHelper.narrow(poa
							.servant_to_reference(itemImpl));
				} catch (WrongPolicy e) {
					e.printStackTrace();
				} catch (ServantNotActive e) {
					e.printStackTrace();
				}
			} else if (type.toUpperCase().equals("ITEMA")) {
				System.out.println("Creating itemA: " + name);
				ItemAImpl itemAImpl = new ItemAImpl(name);
				itemAList.add(itemAImpl);
				busyItemsMap.put(name, true);
				try {
					retItem = ItemHelper.narrow(poa
							.servant_to_reference(itemAImpl));
				} catch (WrongPolicy e) {
					e.printStackTrace();
				} catch (ServantNotActive e) {
					e.printStackTrace();
				}
			} else if (type.toUpperCase().equals("ITEMB")) {
				System.out.println("Creating itemB: " + name);
				ItemBImpl itemBImpl = new ItemBImpl(name);
				itemBList.add(itemBImpl);
				busyItemsMap.put(name, true);
				try {
					retItem = ItemHelper.narrow(poa
							.servant_to_reference(itemBImpl));
				} catch (WrongPolicy e) {
					e.printStackTrace();
				} catch (ServantNotActive e) {
					e.printStackTrace();
				}
			} else if (type.toUpperCase().equals("ITEMC")) {
				System.out.println("Creating itemC: " + name);
				ItemCImpl itemCImpl = new ItemCImpl(name);
				itemCList.add(itemCImpl);
				busyItemsMap.put(name, true);
				try {
					retItem = ItemHelper.narrow(poa
							.servant_to_reference(itemCImpl));
				} catch (WrongPolicy e) {
					e.printStackTrace();
				} catch (ServantNotActive e) {
					e.printStackTrace();
				}
			}
			printCurrentStatus();
		}

		return retItem;
	}

	@Override
	public Item take_item(String name) throws ItemNotExists, ItemBusy {
		System.out.println("In AFactoryImpl::take_item()");

		Item retItem = null;
		synchronized (itemsManageLock) {
			if (!isItemCreated(name)) {
				throw new ItemNotExists("Item not created: " + name);
			}

			if (isItemBusy(name)) {
				throw new ItemBusy("Item busy: " + name);
			}

			ItemImpl itemImpl;
			ItemAImpl itemAImpl;
			ItemBImpl itemBImpl;
			ItemCImpl itemCImpl;
			if ((itemImpl = getItemFromList(name)) != null) {
				System.out.println("returning item: " + name);
				try {
					retItem = ItemHelper.narrow(poa
							.servant_to_reference(itemImpl));
				} catch (WrongPolicy e) {
					e.printStackTrace();
				} catch (ServantNotActive e) {
					e.printStackTrace();
				}
			} else if ((itemAImpl = getItemAFromList(name)) != null) {
				System.out.println("returning itemA: " + name);
				try {
					retItem = ItemHelper.narrow(poa
							.servant_to_reference(itemAImpl));
				} catch (WrongPolicy e) {
					e.printStackTrace();
				} catch (ServantNotActive e) {
					e.printStackTrace();
				}
			} else if ((itemBImpl = getItemBFromList(name)) != null) {
				System.out.println("returning itemB: " + name);
				try {
					retItem = ItemHelper.narrow(poa
							.servant_to_reference(itemBImpl));
				} catch (WrongPolicy e) {
					e.printStackTrace();
				} catch (ServantNotActive e) {
					e.printStackTrace();
				}
			} else if ((itemCImpl = getItemCFromList(name)) != null) {
				System.out.println("returning itemC: " + name);
				try {
					retItem = ItemHelper.narrow(poa
							.servant_to_reference(itemCImpl));
				} catch (WrongPolicy e) {
					e.printStackTrace();
				} catch (ServantNotActive e) {
					e.printStackTrace();
				}
			}
			if (retItem != null) {
				busyItemsMap.put(name, true);
			}
			printCurrentStatus();
		}

		return retItem;
	}

	@Override
	public void release_item(String name) throws ItemNotExists {
		System.out.println("In AFactoryImpl::release_item()");

		synchronized (itemsManageLock) {
			if (!isItemCreated(name)) {
				throw new ItemNotExists("Item not created: " + name);
			}

			busyItemsMap.put(name, false);
			System.out.println("Item " + name + "released");
			printCurrentStatus();
		}

	}

	private boolean isItemCreated(String name) {
		return busyItemsMap.containsKey(name);
	}

	private boolean isItemBusy(String name) {
		return busyItemsMap.get(name);
	}

	private ItemImpl getItemFromList(String name) {
		for (ItemImpl item : itemList) {
			if (item.name().equals(name)) {
				return item;
			}
		}
		return null;
	}

	private ItemAImpl getItemAFromList(String name) {
		for (ItemAImpl item : itemAList) {
			if (item.name().equals(name)) {
				return item;
			}
		}
		return null;
	}

	private ItemBImpl getItemBFromList(String name) {
		for (ItemBImpl item : itemBList) {
			if (item.name().equals(name)) {
				return item;
			}
		}
		return null;
	}

	private ItemCImpl getItemCFromList(String name) {
		for (ItemCImpl item : itemCList) {
			if (item.name().equals(name)) {
				return item;
			}
		}
		return null;
	}

	private void printCurrentStatus() {
		System.out.println("=== CURRENT STATUS: ===");
		System.out.println("Items: " + listToString(itemList));
		System.out.println("ItemsA: " + listAToString(itemAList));
		System.out.println("ItemsB: " + listBToString(itemBList));
		System.out.println("ItemsC: " + listCToString(itemCList));
		System.out.println("Taken status: " + busyItemsMap.toString());
	}

	private String listToString(List<ItemImpl> items) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for (ItemImpl item : items) {
			sb.append(item.name() + ", ");
		}

		sb.append("]");
		return sb.toString();
	}

	private String listAToString(List<ItemAImpl> items) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for (ItemAImpl item : items) {
			sb.append(item.name() + ", ");
		}

		sb.append("]");
		return sb.toString();
	}

	private String listBToString(List<ItemBImpl> items) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for (ItemBImpl item : items) {
			sb.append(item.name() + ", ");
		}

		sb.append("]");
		return sb.toString();
	}

	private String listCToString(List<ItemCImpl> items) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for (ItemCImpl item : items) {
			sb.append(item.name() + ", ");
		}

		sb.append("]");
		return sb.toString();
	}

}
